/***************************************************************************
 *   Copyright (C) 2007 by Phillip Aldridge   *
 *   phillip@imi21.com   *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/
#include "graphview.h"
#include "config.h"

#include <qfont.h>
#include <qcolor.h>
#include <qpen.h>
#include <qdatetime.h>

/**
   This draws all the graphs
   TODO resize to available space on screen
   TODO optimize members and drawing methods
   TODO Add text labels, units and date/time ranges

*/

GraphView::GraphView(QWidget *parent, const char *name)
 : QWidget(parent, name)
{
   setFixedSize(sizeHint());
   width=minimumWidth () ; height=minimumHeight () ;
   setVScalling(50, 0, 10, 0);
}

QSizePolicy GraphView::sizePolicy() const
{
    return QSizePolicy( QSizePolicy::Ignored, QSizePolicy::Ignored );
}

QSize GraphView::sizeHint() const
{
    return QSize(820,450);
}

void GraphView::resizeEvent( QResizeEvent * )
{
 // qDebug("*********** REQIZED ***********");
   width=maximumWidth () ; height=maximumHeight () ;
  adjustSize();
   update();
}

/**
   Set the scalling of each graph
   @pMax : maximum value
   @pMin : Minimum value
   @s: steps for the graph
   @z: zero crossing

*/
void GraphView::setVScalling(int pMax=1, int pMin=-1, int s=1, int z=0 )
{
   if (s==0) s=1;
   vZero=z;
   vStep=s;
   vPosMax=pMax;
   vPosMin=pMin;
   vRange=vPosMax - vPosMin;
   vScale = (float) ((float)graphH / (float)vRange);
}


GraphView::~GraphView()
{


}

/**
   Value lists are set individually
*/
void GraphView::setWindValues( QValueList<float> v)
{
   valuesWind=v;
}
void GraphView::setTempNowValues( QValueList<float> v)
{
   valuesTempNow=v;
}
void GraphView::setTempMinValues( QValueList<float> v)
{
   valuesTempMin=v;
}
void GraphView::setTempMaxValues( QValueList<float> v)
{
   valuesTempMax=v;
}
void GraphView::setRelPressureValues( QValueList<float> v)
{
   valuesRelPressure=v;
}
void GraphView::setDewpointValues( QValueList<float> v)
{
   valuesDewpoint=v;
}
void GraphView::setHumidityValues( QValueList<float> v)
{
   valuesHumidity=v;
}
void GraphView::setRainValues( QValueList<float> v)
{
   valuesRain=v;
}



/**
   if the valuelist contains data then draw it
   TODO the variables sent to setVScalling should
         be collected from the configuration file
*/
void GraphView::plotData( QPainter* p )
{
   QPen pen = p->pen();
   pen.setWidth(0);

   if(! valuesWind.isEmpty ()){

      setVScalling(_WIND_MAX, 0, 10, 0);
      pen.setColor(Qt::green);
      pen.setStyle( Qt::SolidLine);
      p->setPen( pen );
      drawLineChart( p, valuesWind, gx1, gy2 );

      pen.setStyle( Qt::DotLine);
      pen.setColor(Qt::gray);
      p->setPen( pen );
      drawGridH(p, gx1, gy2,valuesTempNow.count());

      pen.setColor(Qt::green);
      pen.setStyle( Qt::DotLine);
      p->setPen( pen );
      drawGridRight(p, gx1, gy2);

      drawLabel( p, gx1, gy2, tr("Wind")+_UNIT_SPEED );
   }

   if(! valuesTempMax.isEmpty ()){

      setVScalling(_TEMP_MAX, _TEMP_MIN, 10, 0);
      pen.setStyle( Qt::SolidLine);
      pen.setColor(QString("#ffd000"));
      p->setPen( pen );
      drawLineChart( p, valuesTempMax, gx1, gy1 );
   }

   if(! valuesTempMin.isEmpty ()){
      setVScalling(_TEMP_MAX, _TEMP_MIN, 10, 0);
      pen.setColor(QString("#dec4ff"));
      pen.setStyle( Qt::SolidLine);
      p->setPen( pen );
      drawLineChart( p, valuesTempMin, gx1, gy1 );
   }

   if(! valuesTempNow.isEmpty ())
   {
      setVScalling(_TEMP_MAX, _TEMP_MIN, 10, 0);
      pen.setStyle( Qt::SolidLine);
      pen.setColor(Qt::red);
      p->setPen( pen );
      drawLineChart( p, valuesTempNow, gx1, gy1 );

      pen.setStyle( Qt::DotLine);
      pen.setColor(Qt::gray);
      p->setPen( pen );
      drawGridH(p, gx1, gy1,valuesTempNow.count());

      pen.setStyle( Qt::DotLine);
      pen.setColor(Qt::red);
      p->setPen( pen );
      drawGrid(p, gx1, gy1);

 drawLabel( p, gx1, gy1, tr("Temperature")+_UNIT_TEMP );
   }

   if(! valuesRelPressure.isEmpty ()){

      setVScalling(_PRESSURE_MAX, _PRESSURE_MIN, 10, _PRESSURE_ZERO);

      pen.setStyle( Qt::DotLine);
      pen.setColor(Qt::gray);
      p->setPen( pen );
      drawGridH(p, gx2, gy2,valuesRelPressure.count());

      pen.setColor(Qt::gray);
      pen.setStyle( Qt::DotLine);
      p->setPen( pen );
      drawGrid(p, gx2, gy2);

      pen.setColor(Qt::darkRed);
      pen.setStyle( Qt::SolidLine);
      p->setPen( pen );
      drawLineChart( p, valuesRelPressure, gx2, gy2 );
      drawLabel( p, gx2, gy2, tr("Pressure")+_UNIT_PRESSURE );
   }

   if(! valuesHumidity.isEmpty ()){

      setVScalling(_HUMIDITY_MAX, _HUMIDITY_MIN, 20, _HUMIDITY_ZERO);

      pen.setStyle( Qt::DotLine);
      pen.setColor(Qt::gray);
      p->setPen( pen );
      drawGridH(p, gx2, gy1,valuesHumidity.count());

      pen.setColor(Qt::cyan );
      pen.setStyle( Qt::DotLine);
      p->setPen( pen );
      drawGrid(p, gx2, gy1);

      pen.setColor(Qt::cyan);
      pen.setStyle( Qt::SolidLine);
      p->setPen( pen );
      drawLineChart( p, valuesHumidity, gx2, gy1 );
      drawLabel( p, gx2, gy1, tr("Humidity")+_UNIT_HUMIDITY );
   }

   if(! valuesDewpoint.isEmpty ()){

      setVScalling(_DEW_MAX, _DEW_MIN, 5, 0);

      pen.setColor(Qt::blue );
      pen.setStyle( Qt::DotLine);
      p->setPen( pen );
      drawGridRight(p, gx2, gy1);

      pen.setColor(Qt::blue );
      pen.setStyle( Qt::SolidLine);
      p->setPen( pen );
      drawLineChart( p, valuesDewpoint, gx2, gy1 );

   }

   if(! valuesRain.isEmpty ()){

      // special scalling for rain bars
      // this calulates the maximum rain value
      // in the given range and auto adapts the scalling
       QValueList<float>::iterator it;
      float max=0;
      for ( it = valuesRain.begin(); it != valuesRain.end(); ++it )
      {
         max=QMAX(max, *it);
      }
      setVScalling((int) max*2, 0, (int)(max/10), 0);

      pen.setStyle( Qt::DotLine);
      pen.setColor(Qt::gray);
      p->setPen( pen );
      drawGridH(p, gx1, gy1,valuesHumidity.count());

      pen.setColor(Qt::darkBlue);
      pen.setStyle( Qt::DotLine);
      p->setPen( pen );
      drawGrid(p, gx1, gy2);

      pen.setStyle( Qt::SolidLine);
      p->setPen( pen );
      drawBarChart( p, valuesRain, gx1, gy2 );

   }
}
/**
   @NAME drawLabel
*/
void GraphView::drawLabel( QPainter* p,int originX, int originY, QString s )
{
   // draw labels   
   QFont f( "Helvetica", 9 );
   p->setFont( f );
   QPen pen = p->pen();
   pen.setColor(Qt::black);
   p->setPen( pen );

    QFontMetrics fm( f );
    int pixelWidth = fm.width( s );
    int pixelHeight = fm.height();

   int y=pixelHeight+originY+3;
   int x=(graphW/2) + originX - (pixelWidth/2);

   p->drawRect(x-4, originY, pixelWidth+8, pixelHeight+6);
   p->drawText( x, y, s );

}
/**
   Bar chart
*/
void GraphView::drawBarChart( QPainter* p, QValueList<float> vData, int originX, int originY)
{
   int step=0, x=0, w ;
   float xScale;

   QPen pen = p->pen();
   pen.setWidth(0);
   p->setPen( pen );

   xScale=(float) ( (float) (graphW-1) / ( vData.count() - 1));

   if (xScale<1) w=1; else w= (int) xScale;
   QValueList<float>::iterator it;

   for ( it = vData.begin(); it != vData.end(); ++it )
   {
      float v=(*it) * vScale; 
      if (v >0.0)  p->drawRect(x+originX, originY+graphH, w, (int) -v);
      step++;
      x = (int)( step * xScale);
   }
}
/**
   Line Chart 
*/
void GraphView::drawLineChart( QPainter* p, QValueList<float> vData, int originX, int originY)
{
   int step=0, xPos=0, x ;
   bool first=true;

   float xScale=(float) ( (float) (graphW-1) / ((float) vData.count() - 1));
   QPen pen = p->pen();
   pen.setWidth(0);
   pen.setJoinStyle(Qt::BevelJoin);
   p->setPen( pen );
   QValueList<float>::iterator it;
   int yPos=vPos( vZero );
   for ( it = vData.begin(); it != vData.end(); ++it )
   {
      int v=(int) vPos(*it);
      x=(int)( step * xScale);
      if (first)
      {
         xPos=x;
         yPos=v;
         first=false;
      }
      p->drawLine(xPos+originX,yPos+originY,x+originX,v+originY);
      xPos = x; yPos = v;
      step++;
   }
}
/**
   Draw the grid on the left along the Y axis
   of the widget based on current scale settings
*/
void GraphView::drawGrid(QPainter* p, int originX, int originY)
{
   QFont fc( "Helvetica", 6 );
   int v;
   //p->setPen( Qt::DotLine);
   for (int i=vPosMin+vStep; i<=(vPosMax-1); i=i+vStep)
   {
      v=vPos(i);
      p->drawLine(originX+1,originY+v,originX+graphW-2,originY+v);
   }
   v=vPos( vZero );
   p->setPen( Qt::SolidLine);
   p->drawLine(originX,originY+v,originX+graphW-2,originY+v);

   // draw labels
   p->setFont( fc );
   QPen pen = p->pen();
   pen.setColor(Qt::black);
   p->setPen( pen );
   QString ht;
   for (int i=vPosMin+vStep; i<=(vPosMax-1); i=i+vStep)
   {
      v=vPos(i);
      ht=QString("%1").arg(i);
      p->drawText( originX+1, originY+v-1, ht );
   }
}
/**
   Draw the on the right side grid along the Y axis
   of the widget based on current scale settings
*/
void GraphView::drawGridRight(QPainter* p, int originX, int originY)
{

   int v;
   //p->setPen( Qt::DotLine);
   for (int i=vPosMin+vStep; i<=(vPosMax-1); i=i+vStep)
   {
      v=vPos(i);
      p->drawLine(originX+1,originY+v,originX+graphW-2,originY+v);
   }
   v=vPos( vZero );
   p->setPen( Qt::SolidLine);
   p->drawLine(originX,originY+v,originX+graphW-2,originY+v);

   // draw labels   
   QFont fc( "Helvetica", 6 );
   p->setFont( fc );
   QPen pen = p->pen();
   pen.setColor(Qt::black);
   p->setPen( pen );
   QString ht;
   for (int i=vPosMin+vStep; i<=(vPosMax-1); i=i+vStep)
   {
      v=vPos(i);
      ht=QString("%1").arg(i);
      p->drawText( originX+graphW-10, originY+v-1, ht );
   }
}

void GraphView::drawGridH(QPainter* p, int originX, int originY, int count)
{
   QPen pen = p->pen();
   pen.setColor(Qt::gray);
   p->setPen( pen );
   // this is to stop too many lines being drawn
   // TODO there must be a better way do this
   if (count>50) count=50;
   float xScale=(float) ( (float) (graphW-1) / ( count - 1));
   int xStart=originX;
   int xEnd=xStart + graphW - 1;
   for (float i=xStart + xScale; i <= xEnd ; i= i + xScale)
   {
      //v=vPos(i);
      p->drawLine((int)i,originY,(int)i,originY+graphH);
   }
}

/**
   Draw the 4 boxes to display the graphs
   TODO I think we are drawing all the boxes each time when we could draw just the individual box for the grap
*/
void GraphView::drawBoxes(QPainter* p)
{
   yAxis=12;
   
   graphW=(width/2)-(yAxis);
   graphH=(height/2)-(yAxis);
   gx1 = yAxis;
   gx2 = graphW+gx1+yAxis;
   gy1 = yAxis;
   gy2 = graphH+gy1+yAxis;

   // draw the boxes to contain graphs
   QPen pen = p->pen();
   pen.setStyle( Qt::SolidLine);
   pen.setWidth(0);
   pen.setColor(Qt::black);
   p->setPen( pen );
   p->drawRect(gx1,gy1,graphW,graphH);//top left temp
   p->drawRect(gx2,gy1,graphW,graphH);//top right dew & humidity
   p->drawRect(gx1,gy2,graphW,graphH);//bottom left wind & rain
   p->drawRect(gx2,gy2,graphW,graphH);//bottom right temp

}

//paint->setWindow( -500,-500, 1000,1000 );
void GraphView::paintEvent( QPaintEvent *e )
{ 
   QPainter painter(this);
   painter.fillRect(0, 0, width, height, Qt::white);
   drawBoxes( &painter );
   plotData( &painter );
}

void GraphView::print( QPainter *p )
{
    //update();
}

/**
   Returns the Y data position
*/
int GraphView::vPos(float p=0)
{
   float i;
   i=p-vPosMin;//minTempNeg;
   i= (i* vScale ); 
   i = graphH-i;
   if (i>=graphH) i--;
   return (int) i;
}
